package com.itcaius.weblog.jwt.utils;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.security.Key;
import java.sql.Date;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Base64;

/**
 * @author Caius
 * @description
 * @since Created in 2025-04-18
 */
@Component
public class JwtTokenHelper implements InitializingBean {
    /**
     * 签发者
     */
    @Value("jwt.issuer")
    private String issuer;
    /**
     * 秘钥
     */
    private Key key;

    /**
     * JWT解析
     */
    private JwtParser jwtParser;

    /**
     * 解码配置文件中配置的 Base64 编码 key 为秘钥
     * @param base64Key 秘钥
     */
    @Value("${jwt.secret}")
    public void setBase64Key(String base64Key){
        key = Keys.hmacShaKeyFor(Base64.getDecoder().decode(base64Key));
    }

    @Value("${jwt.tokenExpireTime}")
    private Long tokenExpireTime;
    /**
     * 初始化 JwtParser
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        // 不同服务器可能存在时钟偏移， setAllowedClockSkewSeconds 设置能容忍的最大时钟误差
        jwtParser = Jwts.parserBuilder().requireIssuer(issuer)
                .setSigningKey(key).setAllowedClockSkewSeconds(10)
                .build();
    }

    /**
     * 生成Token
     * @param username
     * @return
     */
    public String generateToken(String username){
        LocalDateTime now = LocalDateTime.now();
        //Token 失效时间
        LocalDateTime expireTime = now.plusMinutes(tokenExpireTime);

        return Jwts.builder().setSubject(username)
                .setIssuer(issuer)
                .setIssuedAt(Date.from(now.atZone(ZoneId.systemDefault()).toInstant()))
                .setExpiration(Date.from(expireTime.atZone(ZoneId.systemDefault()).toInstant()))
                .signWith(key)
                .compact();
    }

    /**
     * 解析 Token
     * @param token
     * @return
     */
    public Jws<Claims> parseToken(String token){
        try{
            return jwtParser.parseClaimsJws(token);
        }catch (SignatureException | MalformedJwtException | UnsupportedJwtException | IllegalArgumentException e){
            throw new BadCredentialsException("Token 不可用", e);
        }catch (ExpiredJwtException e){
            throw new CredentialsExpiredException("Token 失效", e);
        }
    }

    /**
     * 生成一个 Base64 的安全秘钥
     * @return
     */
    private static String generateKeyForBase64Key(){
        //生成安全秘钥
        SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS512);

        //将秘钥进行 Base64 编码
        String base64Key = Base64.getEncoder().encodeToString(secretKey.getEncoded());

        return base64Key;
    }

    /**
     * 校验 Token 是否可用
     * @param token
     */
    public void validateToken(String token){
        jwtParser.parseClaimsJws(token);
    }

    /**
     * 解析 Token 获取用户名
     * @param token
     * @return
     */
    public String getUsernameByToken(String token){
        try {
            Claims claims = jwtParser.parseClaimsJws(token).getBody();
            String username = claims.getSubject();
            return username;
        } catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
}
